package cn.bdqn.t354.config.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import cn.bdqn.t354.pojo.Right;
import cn.bdqn.t354.service.RightService;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class ShiroConfig {
    @Resource
    RightService rightService;
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    /**
     * 开启shiro方法注解支持
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator=
                new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启spring aop注解支持
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor
    authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor=
                new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 创建领域对象
     * @return
     */
    @Bean
    public MyShiroRealm myShiroRealm(){
        MyShiroRealm myShiroRealm=
                new MyShiroRealm();
        //启用缓存
        myShiroRealm.setCachingEnabled(true);
        //权限信息启用缓存
        myShiroRealm.setAuthorizationCachingEnabled(true);
        //给缓存起名称
        myShiroRealm.setAuthorizationCacheName("authorizationCache");

        //注入密码匹配器
        myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());

        return myShiroRealm;
    }

    /**
     * 创建安全管理员
     * @return
     */
    @Bean
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager=
                new DefaultWebSecurityManager();
        //设置域
        securityManager.setRealm(myShiroRealm());
        //设置记住我
        securityManager.setRememberMeManager(rememberMeManager());
        //注入session管理
        securityManager.setSessionManager(sessionManager());
        //注入cachemanager
        securityManager.setCacheManager(redisCacheManager());

        return securityManager;
    }

    /**
     *
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(){
        ShiroFilterFactoryBean factoryBean=
                new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager());
        //登录路劲
        factoryBean.setLoginUrl("/login");
        //登录成功跳转路劲
        factoryBean.setSuccessUrl("/main");
        //没有权限跳转路径
        factoryBean.setUnauthorizedUrl("/403");

        //过滤器链
        Map<String,String> map=new LinkedHashMap<>();//一定要用LinkedHashMap
        //不需要保护的资源
        map.put("/css/**","anon");
        map.put("/fonts/**","anon");
        map.put("/images/**","anon");
        map.put("/js/**","anon");
        map.put("/localcss/**","anon");
        map.put("/localjs/**","anon");
        map.put("/login","anon");
        map.put("/dologin","anon");

        //退出
        map.put("/logout","logout");

        //要保护
        //静态授权
      /*  map.put("/user/list","perms[用户列表]");
        map.put("/user/add","perms[添加用户]");
//        map.put("/user/edit","perms[修改用户]");
        map.put("/user/delete","perms[删除用户]");*/
        //动态授权
        List<Right> rights = rightService.findAllRights();
        for (Right right : rights) {
            if(right.getRightUrl()!=null&&
                    !"".equals(right.getRightUrl().trim())){
                map.put(right.getRightUrl(),
                        "perms["+right.getRightCode()+"]");
            }
        }

        //剩余的主要登录 就可以访问
        map.put("/**","authc");//这句一定要放在最后

        factoryBean.setFilterChainDefinitionMap(map);

        return factoryBean;
    }

    /**
     * 创建cookie对象
     * @return
     */
    @Bean
    public SimpleCookie rememberMeCookie(){
        //创建cookie对象
        SimpleCookie cookie=new SimpleCookie("rememberMe");
        //设置cookie的有效期
        cookie.setMaxAge(24*24*60);
        return cookie;
    }

    /**
     * 创建cookie管理对象
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        CookieRememberMeManager cookieRememberMeManager=
                new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        cookieRememberMeManager.setCipherKey(Base64
                .decode("4AvVhmFLUs0KTA3Kprsdag=="));
        return cookieRememberMeManager;
    }

    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager=new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);

        return redisManager;
    }

    @Bean
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO=new RedisSessionDAO();
        //注入了redismanager
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    @Bean
    public SessionManager sessionManager(){
        DefaultWebSessionManager defaultWebSessionManager=
                new DefaultWebSessionManager();
        //注入了sessiondao
        defaultWebSessionManager.setSessionDAO(redisSessionDAO());
        return defaultWebSessionManager;
    }

    @Bean
    public RedisCacheManager redisCacheManager(){
        RedisCacheManager redisCacheManager=
                new RedisCacheManager();
        //注入redismanager
        redisCacheManager.setRedisManager(redisManager());
        //缓存的名称
        redisCacheManager.setPrincipalIdFieldName("usrName");
        //缓存有效期
        redisCacheManager.setExpire(30*60);

        return redisCacheManager;
    }

    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher(){
        HashedCredentialsMatcher hashedCredentialsMatcher=
                new HashedCredentialsMatcher();
        //设置算法
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        //设置加密次数
        hashedCredentialsMatcher.setHashIterations(2);
        return hashedCredentialsMatcher;
    }
}
